//-----------------------------------------------------------------------------
// UpdateSubscription
//
// Copyright (c) MetaSwitch 2006
// Author: Alex Davies
//
// Sample application demonstrating the SOAP Sh interface to the MetaView
// Server.  This application uses Sh-Pull to display a subscriber's current
// settings for a particular call service, and then sends an Sh-Update to
// change whether the subscriber is subscribed to that service, using the
// sequence number to avoid conflicting updates.  Finally it makes a second
// Sh-Pull request to display the new configuration.  It uses Apache Axis and
// the "untyped" WSDL file.
//
// See the readme file for more information.
//-----------------------------------------------------------------------------

import javax.xml.rpc.holders.*;
import javax.xml.soap.SOAPException;

import org.apache.axis.message.MessageElement;

import com.MetaSwitch.EMS.SOAP.*;
import com.MetaSwitch.EMS.SOAP.holders.*;

public class UpdateSubscription
{
  private static final String USAGE = "Usage: UpdateSubscription " +
                                      "<Directory number> " +
                                      "<Service indication> <subscribed | " +
                                      "unsubscribed | default>";
  private static final String TRUE = "True";
  private static final String FALSE = "False";

  private static ShUntypedUtilities utilities = new ShUntypedUtilities();

  public static void main(String[] args)
  {
    StringHolder dNHolder = new StringHolder();
    StringHolder servIndHolder = new StringHolder();
    StringHolder subscribedHolder = new StringHolder();

    IntHolder resultCodeHolder = new IntHolder();
    TExtendedResultHolder extendedResultHolder = new TExtendedResultHolder();
    TUserDataHolder userDataHolder = new TUserDataHolder();

    try
    {
      //-----------------------------------------------------------------------
      // Extract information from the command line arguments.
      //-----------------------------------------------------------------------
      getParameters(args,
                    dNHolder,
                    servIndHolder,
                    subscribedHolder);

      //-----------------------------------------------------------------------
      // Connect to the Sh service and send in a Pull request.
      //-----------------------------------------------------------------------
      ShServiceLocator locator = new ShServiceLocator();

      Sh shInstance = locator.getShService();

      shInstance.shPull(dNHolder.value,
                        0,
                        servIndHolder.value,
                        utilities.ORIGIN_HOST,
                        resultCodeHolder,
                        extendedResultHolder,
                        userDataHolder);

      //-----------------------------------------------------------------------
      // Check whether the request succeeded and display the "before update"
      // value of each of the fields.
      //-----------------------------------------------------------------------
      utilities.checkResultCode(resultCodeHolder.value,
                                extendedResultHolder.value,
                                userDataHolder.value);

      System.out.println("Old settings:");
      utilities.displayFields(userDataHolder.value);

      //-----------------------------------------------------------------------
      // Update the user data and send it back.  Check that the request
      // succeeded.
      //-----------------------------------------------------------------------
      utilities.incrementSequenceNumber(userDataHolder.value);

      updateSubscribedField(userDataHolder.value, subscribedHolder.value);

      shInstance.shUpdate(dNHolder.value,
                          0,
                          userDataHolder.value,
                          utilities.ORIGIN_HOST,
                          resultCodeHolder,
                          extendedResultHolder);

      utilities.checkResultCode(resultCodeHolder.value,
                                extendedResultHolder.value,
                                userDataHolder.value);

      //-----------------------------------------------------------------------
      // Finally, call ShPull again and output the "after update" field values
      // to show the change has been successful.
      //-----------------------------------------------------------------------
      shInstance.shPull(dNHolder.value,
                        0,
                        servIndHolder.value,
                        utilities.ORIGIN_HOST,
                        resultCodeHolder,
                        extendedResultHolder,
                        userDataHolder);

      utilities.checkResultCode(resultCodeHolder.value,
                                extendedResultHolder.value,
                                userDataHolder.value);

      System.out.println("New settings:");
      utilities.displayFields(userDataHolder.value);
    }
    catch (MetaSwitchShInterfaceException e)
    {
      System.err.println(e.getMessage());
      System.err.println(USAGE);
    }
    catch (org.apache.axis.AxisFault e)
    {
      System.err.println("Problem connecting to MetaView server: " + e);
      System.err.println(USAGE);
    }
    catch (javax.xml.rpc.ServiceException e)
    {
      System.err.println("Could not connect to Sh service");
      System.err.println(USAGE);
    }
    catch (Exception e)
    {
      System.err.println("Unexpected error \"" + e
                         + "\" in retrieving data");
      e.printStackTrace(System.err);
      System.err.println(USAGE);
    }
  }

  /**
   * Parse the command line arguments and extract the necessary information.
   *
   * All three parameters are required:
   * -  the subscriber's DN
   * -  the call service
   * -  the new value for the subscription.
   *
   * @param args        IN  The arguments provided at the command line.
   * @param dN          OUT The directory number to update.
   * @param servInd     OUT The service indication to update.
   * @param subscription
   *                    OUT Whether to subscribe to this service, unsubscribe
   *                    from the service or return to the default value.
   *
   * @exception WrongParametersException
   */
  private static void getParameters(String[] args,
                                    StringHolder dN,
                                    StringHolder servInd,
                                    StringHolder subscription)
    throws WrongParametersException
  {
    if (args.length != 3)
    {
      throw new WrongParametersException("Wrong number of parameters.");
    }

    dN.value = args[0];
    servInd.value = "Meta_Subscriber_" + args[1];
    subscription.value = args[2].toLowerCase();

    if (!(subscription.value.equals("subscribed")) &&
        !(subscription.value.equals("unsubscribed")) &&
        !(subscription.value.equals("default")))
    {
      throw new WrongParametersException("SubscribedField may only be one " +
                                         "of subscribed, unsubscribed or " +
                                         "default.");
    }
  }

  /**
   * Finds the "Subscribed" field within the user data and sets it to a new
   * value.
   *
   * @param userData    IN/OUT The user data to update.
   * @param subscription
   *                    IN     Whether to subscribe or unsubscribe from the
   *                           service.
   *
   * @exception NoSubscribedFieldException
   */
  public static void updateSubscribedField(TUserData userData,
                                           String subscription)
    throws NoSubscribedFieldException,
           SOAPException
  {
    //-------------------------------------------------------------------------
    // Dig down to the "Subscribed" field and fetch the elements corresponding
    // to its value and whether it is inheriting the default value.
    //-------------------------------------------------------------------------
    MessageElement fieldGroupElement =
                                      utilities.getFieldGroupElement(userData);
    MessageElement subscribedElement =
              fieldGroupElement.getChildElement(ShUntypedUtilities.SUBSCRIBED);

    //-------------------------------------------------------------------------
    // Ensure that this is call service data by checking that it actually has a
    // "Subscribed" field.
    //-------------------------------------------------------------------------
    if (subscribedElement == null)
    {
      throw new NoSubscribedFieldException("There is no \"Subscribed\" " +
                                           "field in the requested Service " +
                                           "Indication");
    }

    //-------------------------------------------------------------------------
    // Continue digging down to contents of "Subscribed" field.
    //-------------------------------------------------------------------------
    MessageElement subscribedValueElement =
                   subscribedElement.getChildElement(ShUntypedUtilities.VALUE);
    MessageElement subscribedUseDefaultElement =
             subscribedElement.getChildElement(ShUntypedUtilities.USE_DEFAULT);

    //-------------------------------------------------------------------------
    // Determine what change is needed to this call service and update the
    // "Subscribed" field.
    //-------------------------------------------------------------------------
    if (subscription.equals("subscribed"))
    {
      subscribedValueElement.setValue(TRUE);
      subscribedUseDefaultElement.setValue(FALSE);
    }
    else if (subscription.equals("unsubscribed"))
    {
      subscribedValueElement.setValue(FALSE);
      subscribedUseDefaultElement.setValue(FALSE);
    }
    else if (subscription.equals("default"))
    {
      subscribedUseDefaultElement.setValue(TRUE);
    }

    //-------------------------------------------------------------------------
    // Remove all the other field elements from the user data.
    //-------------------------------------------------------------------------
    fieldGroupElement.removeContents();
    fieldGroupElement.addChild(subscribedElement);
  }
}

//-----------------------------------------------------------------------------
// NoSubscribedFieldException
//
// Indicates that user data did not contain a "Subscribed" field, suggesting
// that it was not call service information.
//-----------------------------------------------------------------------------
class NoSubscribedFieldException extends MetaSwitchShInterfaceException
{
  NoSubscribedFieldException(String s)
  {
    super(s);
  }
}
